﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using System.Collections;
using RestaurantBooker.Helpers;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;

namespace RrestarauntBooker.Helpers
{
    public static class CommonExtensions
    {
        public static Color ColorFromARGBString(string color)
        {            
            
            byte a = (byte)(System.Convert.ToUInt32(color.Substring(0, 2), 16));

            byte r = (byte)(System.Convert.ToUInt32(color.Substring(2, 2), 16));
            byte g = (byte)(System.Convert.ToUInt32(color.Substring(4, 2), 16));
            byte b = (byte)(System.Convert.ToUInt32(color.Substring(6, 2), 16));

            return Color.FromArgb(a, r, g, b);
        }
    }

    

    //public static class AppColumnsItemsControlExtension
    //{
    //    public static AppColumnList GetSourceAppColumnList(this ItemsControl itemsSource)
    //    {
    //        AppColumnList sourceAppColumnList = itemsSource.ItemsSource as AppColumnList;

    //        if (sourceAppColumnList == null)
    //            if (itemsSource.ItemsSource is ICollectionView)
    //                sourceAppColumnList = (itemsSource.ItemsSource as ICollectionView).SourceCollection as AppColumnList;

    //        if (sourceAppColumnList == null)
    //            return null;

    //        return sourceAppColumnList;
    //    }
    //}

    // <summary>
    /// Reference Article http://www.codeproject.com/KB/tips/SerializedObjectCloner.aspx
    /// 
    /// Provides a method for performing a deep copy of an object.
    /// Binary Serialization is used to perform the copy.
    /// </summary>

    //private class PropertyCache
    //{
    //    internal PropertyInfo Properties;
    //}

    public class TypeCache
    {
        internal List<PropertyInfo> Properties;

        internal static TypeCache GetCacheFor(object source)
        {
            TypeCache cacheItem = new TypeCache();

            var props = source.GetType().GetProperties();
            
            cacheItem.Properties = (from Property in props
             where Property.GetGetMethod() != null && Property.GetSetMethod() != null
             select Property).ToList();

            //cacheItem.Properties[0].

            return cacheItem;
        }
    }

    public static class ObjectCopier
    {
        public static T xClone<T>(this T source)
        {
            T Cloned = (T)Activator.CreateInstance(source.GetType());
            source.xCopyTo(Cloned);
            return Cloned;
        }

        private static Dictionary<String, TypeCache> cache = new Dictionary<string, TypeCache>();

        public static void xCopyTo<T>(this T source, T destination, params string[] skipProps)
        {
            if (destination == null)
                 destination = (T)Activator.CreateInstance(source.GetType());

            TypeCache cachedType;
            if (cache.ContainsKey(source.GetType().Name))
                cachedType = cache[source.GetType().Name];
            else
            {
                cachedType = TypeCache.GetCacheFor(source);
                cache.Add(source.GetType().Name, cachedType);
            }

            //var props = typeof(T).GetProperties();
            //(from Property in props
            // where Property.GetGetMethod() != null && Property.GetSetMethod() != null
            // select Property).ToList().ForEach(Property =>
            foreach (PropertyInfo Property in cachedType.Properties)
             {

                 // Check if the object inherits from ICollection (The ICollection interface is the base interface
                 // for classes in the System.Collections namespace
                 if (!Property.PropertyType.GetInterfaces().Contains(typeof(ICollection)) && Property.Name != "Name" && (skipProps == null || (!skipProps.Contains<String>(Property.Name))))
                 {
                     object PropertyValue = Property.GetGetMethod().Invoke(source, Property.GetGetMethod().GetParameters());

                     if (PropertyValue != null && PropertyValue is DependencyObject) 
                     {
                         PropertyValue = PropertyValue.xClone(); 
                     }

                     // if PropertyValue is not a value type and is itself a dependency object, 
                     // it must be "cloned" as well
                     Property.GetSetMethod().Invoke(destination, new object[] { PropertyValue });
                 }
                 else if (Property.PropertyType.GetInterfaces().Contains(typeof(ICollection)) && (skipProps == null || (!skipProps.Contains<String>(Property.Name))))
                 {
                     ICollection CollectionValue = (ICollection)Property.GetGetMethod().Invoke(source, new object[] { });
                     Property.SetValue(destination, CollectionValue, null);
                 }
             };
        }



        //public static void xCopyTo<T>(this T source, T destination, params string[] skipProps)
        //{
        //    if (destination == null)
        //        destination = (T)Activator.CreateInstance(source.GetType());

        //    TypeCache cachedType = cache[source.GetType().Name];
        //    if (cachedType == null)
        //    {
        //        cachedType = TypeCache.GetCacheFor(source);
        //        cache.Add(source.GetType().Name, cachedType);
        //    }

        //    var props = typeof(T).GetProperties();
        //    (from Property in props
        //     where Property.GetGetMethod() != null && Property.GetSetMethod() != null
        //     select Property).ToList().ForEach(Property =>
        //     {

        //         // Check if the object inherits from ICollection (The ICollection interface is the base interface
        //         // for classes in the System.Collections namespace
        //         if (!Property.PropertyType.GetInterfaces().Contains(typeof(ICollection)) && Property.Name != "Name" && (skipProps == null || (!skipProps.Contains<String>(Property.Name))))
        //         {
        //             object PropertyValue = Property.GetGetMethod().Invoke(source, Property.GetGetMethod().GetParameters());

        //             if (PropertyValue != null && PropertyValue is DependencyObject)
        //             {
        //                 Debug.WriteLine("Dependency " + Property.Name);
        //                 PropertyValue = PropertyValue.xClone();
        //             }

        //             // if PropertyValue is not a value type and is itself a dependency object, 
        //             // it must be "cloned" as well
        //             Property.GetSetMethod().Invoke(destination, new object[] { PropertyValue });
        //         }
        //         else if (Property.PropertyType.GetInterfaces().Contains(typeof(ICollection)) && (skipProps == null || (!skipProps.Contains<String>(Property.Name))))
        //         {
        //             Debug.WriteLine("List " + Property.Name);
        //             ICollection CollectionValue = (ICollection)Property.GetGetMethod().Invoke(source, new object[] { });
        //             Property.SetValue(destination, CollectionValue, null);
        //         }
        //     });
        //}
    }
}



namespace System
{
    public static class SystemEx
    {
        //public static T PropertyValueByName<T>(this object obj, T defaultValue)
        //{
        //    object value = obj.GetType().GetProperty("PropertyName").GetValue(obj,
        //                null);
        //}

        public static T PropertyValueByName<T>(this object obj, string propertyName)
        {
            PropertyInfo pi = obj.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static );
            pi = obj.GetType().GetProperty(propertyName, typeof(T));
            if (pi == null)
                throw new ArgumentException(String.Format("Property with name '{0}' not found", propertyName));
            
            return (T)pi.GetValue(obj, null);
        }
    }
}

namespace System.Linq          
{
    public static class EnumerableEx
    {
        public static ulong Sum<TSource>(this IEnumerable<TSource> source, Func<TSource, ulong?> selector)
        {
            ulong res = 0;
            foreach (var s in source)
            {                
                res += selector.Invoke(s) ?? 0;
            }
            return res;
        }

        /// <summary>
        /// Copmute Summ of the values ulong? selector.
        /// If ALL selector is NULL will be return NULL!
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source">list of the ulong? values </param>
        /// <param name="selector">item</param>
        /// <returns>
        /// If ALL selector is NULL will be return NULL, else 
        /// all null <paramref name="selector"/> values will be converted to zero!
        /// </returns>
        public static ulong? NullableSum<TSource>(this IEnumerable<TSource> source, Func<TSource, ulong?> selector)
        {
            ulong res = 0;
            bool hasNotNull = false;
            ulong? currentValue = null;
            foreach (var s in source)
            {
                currentValue = selector.Invoke(s);

                if (currentValue.HasValue)
                    hasNotNull = true;
                res += currentValue ?? 0;
            }
            if (hasNotNull)
                return res;
            else
                return null;
        }



        /// <summary>
        /// Copmute Summ of the values double? selector.
        /// If ALL selector is NULL will be return NULL!
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source">list of the double? values </param>
        /// <param name="selector">item</param>
        /// <returns>
        /// If ALL selector is NULL will be return NULL, else 
        /// all null <paramref name="selector"/> values will be converted to zero!
        /// </returns>
        public static double? NullableSum<TSource>(this IEnumerable<TSource> source, Func<TSource, double?> selector)
        {
            double res = 0;
            bool hasNotNull = false;
            double? currentValue = null;
            foreach (var s in source)
            {
                currentValue = selector.Invoke(s);

                if (currentValue.HasValue)
                    hasNotNull = true;
                res += currentValue ?? 0;
            }
            if (hasNotNull)
                return res;
            else
                return null;
        }

    }
}
namespace System.Collections.ObjectModel
{
    public static class IListExtensions
    {

        public static void InsertRange<T>(this IList<T> list, int index, IList<T> insertedList)
        {
            if (index > list.Count)
                return;

            if (insertedList == null)
                throw new ArgumentNullException("insertedList");

            if (insertedList.Count == 0)
                return;

            for (int i = 0; i < insertedList.Count; i++)
            {
                list.Insert(i + index, insertedList[i]);
            }
        }

        public static void AddRange<T>(this IList<T> list, IList<T> insertedList)
        {
            list.InsertRange(list.Count, insertedList);
        }

        public static int IndexOfByData<T>(this IList<T> list, T data,  Func<T, T, bool> comparer)
        {
            for (int i = 0; i < list.Count; i++)
                if (comparer(data, list[i]))
                    return i;
            return -1;
        }        
    }
}

namespace System
{


    /// <summary>
    /// Enum extensinal method
    /// </summary>
    public static class EnumExtension
    {
        public static Array GetValues(Type enumType)
        {
            FieldInfo[] fields = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);

            Array array = Array.CreateInstance(enumType, fields.Length);

            for (int i = 0; i < fields.Length; i++)
            {
                var obj = fields[i].GetValue(null);
                array.SetValue(obj, i);
            }
            return array;
        }

        public static void FillList(Type enumType, IList destinationList)
        {
            if (destinationList != null)
            {
                var values = GetValues(enumType);
                foreach (var en in values)
                    destinationList.Add(en);
            }
        }

    }
}
